import { AbstractSeeder } from '../abstract';
import { Prisma, PrismaClient } from '../../../src/generated/prisma';
import { hash } from 'bcrypt';
import { USER_DATA } from './user.data';

export default class UserSeed extends AbstractSeeder {
  name = 'User' as const;
  data = USER_DATA;

  async exec(tx: Prisma.TransactionClient): Promise<void> {
    const deptMap = new Map(
      (await tx.department.findMany({ select: { id: true, name: true } })).map(d => [ d.name, d.id ]),
    );
    const roleMap = new Map(
      (await tx.role.findMany({ select: { id: true, code: true } })).map(r => [ r.code, r.id ]),
    );

    for (const u of this.data) {
      const hashed = await hash(u.password, 10);
      const user = await tx.user.upsert({
        where: { username: u.username },
        update: {},
        create: {
          name: u.name,
          username: u.username,
          password: hashed,
          email: u.email,
          departmentId: deptMap.get(u.departmentName)!,
        },
      });

      const userRoles = u.roleCodes.map(code => ({
        userId: user.id,
        roleId: roleMap.get(code)!,
      }));
      await Promise.all(
        userRoles.map(ur =>
          tx.userRole.upsert({
            where: { userId_roleId: ur },
            update: {},
            create: ur,
          }),
        ),
      );
    }
  }
}

if (require.main === module) {
  const prisma = new PrismaClient();
  new UserSeed()
    .run(prisma)
    .catch(e => {
      console.error(e)
      process.exit(1)
    })
    .finally(() => prisma.$disconnect());
}
